/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab-apps.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include "GuiUpdater.h"
#include <dylab/simulation/Simulation.h>

using namespace dylab;
//===========================================================================================
void GuiUpdater::LogListener::logMessage(const String & _message)
{	
	ComGfx::ScopedExLock(mSimulation->getGfx())->getGuiSystem()->setGuiElementCaption("Core/DebugText", _message);
}
//-----------------------------------------------------------------------------

//===========================================================================================
GuiUpdater::GuiUpdater()
: ComEventListener("guiUpdater")
, mSimulation(NULL), mUpdateTimeBuffer(0), mNoFramesToInitAvgStats(4), mAvgStatsQueueMaxSize(64)
{ 
    mStats.worstFPS = mStats.bestFPS = mStats.currFPS = mStats.triangleCount = mStats.triangleCountMax = 0;
    mStats.resetStatTimes();
	mAvgStats.worstFPS = mAvgStats.bestFPS = mAvgStats.currFPS = mAvgStats.triangleCount = mAvgStats.triangleCountMax = 0;
	mAvgStats.resetStatTimes();
}
//-----------------------------------------------------------------------------
GuiUpdater::~GuiUpdater()
{
}
//-----------------------------------------------------------------------------
String GuiUpdater::getDescription() const
{
    return "guiUpdater";
}
//-----------------------------------------------------------------------------
void GuiUpdater::initialize(Simulation * _parentSimulation)
{
    // check argument
    DYLAB_ASSERT(_parentSimulation != NULL);

    // store the simulation pointer
    mSimulation = _parentSimulation;
}
//-----------------------------------------------------------------------------
void GuiUpdater::processEvent(const GfxEvent & _gfxEvent)
{
    // update debug stats info
    mUpdateTimeBuffer += _gfxEvent.getFrameDurationMS();
    if (mUpdateTimeBuffer >= 1000) 
    {
        mUpdateTimeBuffer = 0;
        _updateGui();
    }
}
//-----------------------------------------------------------------------------
void GuiUpdater::processGfxStatistics()
{
    if (mStats.triangleCount > mStats.triangleCountMax)
        mStats.triangleCountMax = mStats.triangleCount;
}
//-----------------------------------------------------------------------------
void GuiUpdater::_updateGui()
{
	// update average statistics
	if (mNoFramesToInitAvgStats == 0)
	{
		if (mAvgStatsQueue.size() == mAvgStatsQueueMaxSize)
			mAvgStatsQueue.pop_back();
		mAvgStatsQueue.push_front(mStats);

		// compute average statistics from the queue
		mAvgStats.currFPS = mAvgStats.triangleCount = 0;
		mAvgStats.resetStatTimes();
		for (std::list<Statistics>::iterator stat = mAvgStatsQueue.begin(); stat != mAvgStatsQueue.end(); stat++)
		{			
			mAvgStats.currFPS += stat->currFPS,
			mAvgStats.triangleCount += stat->triangleCount,
			mAvgStats.techniqueTime += stat->techniqueTime, 
			mAvgStats.integratorTime += stat->integratorTime, 
			mAvgStats.collisionTime += stat->collisionTime, 
			mAvgStats.renderingTime += stat->renderingTime, 
			mAvgStats.inputTime += stat->inputTime, 
			mAvgStats.hapticsTime += stat->hapticsTime, 
			mAvgStats.eventsTime += stat->eventsTime;
		}
		mAvgStats.currFPS /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.triangleCount /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.techniqueTime /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.integratorTime /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.collisionTime /= static_cast<uint32_t>(mAvgStatsQueue.size()), 
		mAvgStats.renderingTime /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.inputTime /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.hapticsTime /= static_cast<uint32_t>(mAvgStatsQueue.size()),
		mAvgStats.eventsTime /= static_cast<uint32_t>(mAvgStatsQueue.size());
	}
	else
	{
		mNoFramesToInitAvgStats--;
	}

    // calculate the ratios
    real_t totalTime = mStats.techniqueTime + mStats.integratorTime + mStats.hapticsTime
        + mStats.renderingTime + mStats.collisionTime + mStats.inputTime + mStats.eventsTime;
    uint32_t techniqueRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.techniqueTime / totalTime);
    uint32_t integratorRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.integratorTime / totalTime);
    uint32_t renderingRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.renderingTime / totalTime);
    uint32_t collisionRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.collisionTime / totalTime);
    uint32_t inputRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.inputTime / totalTime);
    uint32_t hapticsRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.hapticsTime / totalTime);
    uint32_t eventsRatio = static_cast<uint32_t>(DYLAB_R(100) * mStats.eventsTime / totalTime);

    // calculate the average ratios
    real_t avg_totalTime = mAvgStats.techniqueTime + mAvgStats.integratorTime + mAvgStats.hapticsTime
        + mAvgStats.renderingTime + mAvgStats.collisionTime + mAvgStats.inputTime + mAvgStats.eventsTime;
    uint32_t avg_techniqueRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.techniqueTime / avg_totalTime);
    uint32_t avg_integratorRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.integratorTime / avg_totalTime);
    uint32_t avg_renderingRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.renderingTime / avg_totalTime);
    uint32_t avg_collisionRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.collisionTime / avg_totalTime);
    uint32_t avg_inputRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.inputTime / avg_totalTime);
    uint32_t avg_hapticsRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.hapticsTime / avg_totalTime);
    uint32_t avg_eventsRatio = static_cast<uint32_t>(DYLAB_R(100) * mAvgStats.eventsTime / avg_totalTime);

    // update the gui system
    ComGfx::IGuiSystem::ScopedExLock guiSystem(mSimulation->getGfx());        
	guiSystem->setGuiElementCaption("Core/CurrFps", String::fmt("Current FPS: %1%", mStats.currFPS));
    guiSystem->setGuiElementCaption("Core/BestFps", String::fmt("(%1%)", mAvgStats.currFPS));
    guiSystem->setGuiElementCaption("Core/NumTris", String::fmt("Triangles: %1% (%2%)", mStats.triangleCount, mAvgStats.triangleCount));
    guiSystem->setGuiElementCaption("Core/TechniqueTime", String::fmt("%.2d", mStats.techniqueTime));
    guiSystem->setGuiElementCaption("Core/AvgTechniqueTime", String::fmt("(%.2d)", mAvgStats.techniqueTime));
    guiSystem->setGuiElementCaption("Core/TechniqueRatio", String::fmt(techniqueRatio));
    guiSystem->setGuiElementCaption("Core/AvgTechniqueRatio", String::fmt("(%1%)", avg_techniqueRatio));
    guiSystem->setGuiElementCaption("Core/AvgIntegratorTime", String::fmt("(%.2d)", mAvgStats.integratorTime));
    guiSystem->setGuiElementCaption("Core/IntegratorRatio", String::fmt(integratorRatio));
    guiSystem->setGuiElementCaption("Core/AvgIntegratorRatio", String::fmt("(%1%)", avg_integratorRatio));
    guiSystem->setGuiElementCaption("Core/AvgRenderingTime", String::fmt("(%.2d)", mAvgStats.renderingTime));
    guiSystem->setGuiElementCaption("Core/RenderingRatio", String::fmt(renderingRatio));
    guiSystem->setGuiElementCaption("Core/AvgRenderingRatio", String::fmt("(%1%)", avg_renderingRatio));
    guiSystem->setGuiElementCaption("Core/AvgCollisionsTime", String::fmt("(%.2d)", mAvgStats.collisionTime));
    guiSystem->setGuiElementCaption("Core/CollisionsRatio", String::fmt(collisionRatio));
    guiSystem->setGuiElementCaption("Core/AvgCollisionsRatio", String::fmt("(%1%)", avg_collisionRatio));
    guiSystem->setGuiElementCaption("Core/AvgInputTime", String::fmt("(%.2d)", mAvgStats.inputTime));
    guiSystem->setGuiElementCaption("Core/InputRatio", String::fmt(inputRatio));
    guiSystem->setGuiElementCaption("Core/AvgInputRatio", String::fmt("(%1%)", avg_inputRatio));
    guiSystem->setGuiElementCaption("Core/AvgHapticsTime", String::fmt("(%.2d)", mAvgStats.hapticsTime));
    guiSystem->setGuiElementCaption("Core/HapticsRatio", String::fmt(hapticsRatio));
    guiSystem->setGuiElementCaption("Core/AvgHapticsRatio", String::fmt("(%1%)", avg_hapticsRatio));
    guiSystem->setGuiElementCaption("Core/AvgEventsTime", String::fmt("(%.2d)", mAvgStats.eventsTime));
    guiSystem->setGuiElementCaption("Core/EventsRatio", String::fmt(eventsRatio));
    guiSystem->setGuiElementCaption("Core/AvgEventsRatio", String::fmt("(%1%)", avg_eventsRatio));
}
//-----------------------------------------------------------------------------